home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / lmgr / lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  24.5 KB  |  1,011 lines

  1. /*
  2.  * lock.c -- simple lock acquisition
  3.  *
  4.  *  Outside modules can create a lock table and acquire/release
  5.  *  locks.  A lock table is a shared memory hash table.  When
  6.  *  a process tries to acquire a lock of a type that conflicts
  7.  *  with existing locks, it is put to sleep using the routines
  8.  *  in storage/lmgr/proc.c.
  9.  *
  10.  *  Interface:
  11.  *
  12.  *  LockAcquire(), LockRelease(), LockTabInit().
  13.  *
  14.  *  LockReplace() is called only within this module and by the
  15.  *      lkchain module.  It releases a lock without looking
  16.  *     the lock up in the lock table.
  17.  *
  18.  *  NOTE: This module is used to define new lock tables.  The
  19.  *    multi-level lock table (multi.c) used by the heap
  20.  *    access methods calls these routines.  See multi.c for
  21.  *    examples showing how to use this interface.
  22.  *
  23.  * $Header: /private/postgres/src/storage/lmgr/RCS/lock.c,v 1.23 1992/06/17 04:57:39 mer Exp $
  24.  */
  25. #include "storage/shmem.h"
  26. #include "storage/spin.h"
  27. #include "storage/proc.h"
  28. #include "storage/lock.h"
  29. #include "utils/hsearch.h"
  30. #include "utils/log.h"
  31. #include "access/xact.h"
  32.  
  33. #ifndef LOCK_MGR_DEBUG
  34.  
  35. #define LOCK_PRINT(where,tag,type)
  36. #define XID_PRINT(where,xidentP)
  37.  
  38. #else LOCK_MGR_DEBUG
  39.  
  40. #define LOCK_PRINT(where,tag,type)\
  41.   elog(DEBUG, "%s: rel (%d) dbid (%d) tid (%d,%d) type (%d)\n",where, \
  42.      tag->relId, tag->dbId, \
  43.      ( (tag->tupleId.blockData.data[0] >= 0) ? \
  44.         BlockIdGetBlockNumber(&tag->tupleId.blockData) : -1 ), \
  45.      tag->tupleId.positionData, \
  46.      type);
  47.  
  48. #define XID_PRINT(where,xidentP)\
  49.   elog(DEBUG,\
  50.        "%s:xid (%d) pid (%d) lock (%x) nHolding (%d) holders (%d,%d,%d,%d,%d)",\
  51.        where,\
  52.        xidentP->tag.xid,\
  53.        xidentP->tag.pid,\
  54.        xidentP->tag.lock,\
  55.        xidentP->nHolding,\
  56.        xidentP->holders[1],\
  57.        xidentP->holders[2],\
  58.        xidentP->holders[3],\
  59.        xidentP->holders[4],\
  60.        xidentP->holders[5]);
  61.  
  62. #endif LOCK_MGR_DEBUG
  63.  
  64. void LockTypeInit ARGS((
  65.     LOCKTAB *ltable, 
  66.     MASK *conflictsP, 
  67.     int *prioP, 
  68.     int ntypes
  69. ));
  70.  
  71. extern int MyPid;        /* For parallel backends w/same xid */
  72. SPINLOCK LockMgrLock;        /* in Shmem or created in CreateSpinlocks() */
  73.  
  74. /* This is to simplify/speed up some bit arithmetic */
  75.  
  76. static MASK    BITS_OFF[MAX_LOCKTYPES];
  77. static MASK    BITS_ON[MAX_LOCKTYPES];
  78.  
  79. /* -----------------
  80.  * XXX Want to move this to this file
  81.  * -----------------
  82.  */
  83. static bool LockingIsDisabled;
  84.  
  85. /* ------------------
  86.  * from storage/ipc/shmem.c
  87.  * ------------------
  88.  */
  89. extern HTAB *ShmemInitHash();
  90.  
  91. /* -------------------
  92.  * map from tableId to the lock table structure
  93.  * -------------------
  94.  */
  95. LOCKTAB *AllTables[MAX_TABLES];
  96.  
  97. /* -------------------
  98.  * no zero-th table
  99.  * -------------------
  100.  */
  101. int    NumTables = 1;
  102.  
  103. /* -------------------
  104.  * InitLocks -- Init the lock module.  Create a private data
  105.  *    structure for constructing conflict masks.
  106.  * -------------------
  107.  */
  108. void
  109. InitLocks()
  110. {
  111.   int i;
  112.   int bit;
  113.  
  114.   bit = 1;
  115.   /* -------------------
  116.    * remember 0th locktype is invalid
  117.    * -------------------
  118.    */
  119.   for (i=0;i<MAX_LOCKTYPES;i++,bit <<= 1)
  120.   {
  121.     BITS_ON[i] = bit;
  122.     BITS_OFF[i] = ~bit;
  123.   }
  124. }
  125.  
  126. /* -------------------
  127.  * LockDisable -- sets LockingIsDisabled flag to TRUE or FALSE.
  128.  * ------------------
  129.  */
  130. void
  131. LockDisable(status)
  132. int status;
  133. {
  134.   LockingIsDisabled = status;
  135. }
  136.  
  137.  
  138. /*
  139.  * LockTypeInit -- initialize the lock table's lock type
  140.  *    structures
  141.  *
  142.  * Notes: just copying.  Should only be called once.
  143.  */
  144. static
  145. void
  146. LockTypeInit(ltable, conflictsP, prioP, ntypes)
  147. LOCKTAB    *ltable;
  148. MASK    *conflictsP;
  149. int    *prioP;
  150. int     ntypes;
  151. {
  152.   int    i;
  153.  
  154.   ltable->ctl->nLockTypes = ntypes;
  155.   ntypes++;
  156.   for (i=0;i<ntypes;i++,prioP++,conflictsP++)
  157.   {
  158.     ltable->ctl->conflictTab[i] = *conflictsP;
  159.     ltable->ctl->prio[i] = *prioP;
  160.   }
  161. }
  162.  
  163. /*
  164.  * LockTabInit -- initialize a lock table structure
  165.  *
  166.  * Notes:
  167.  *    (a) a lock table has four separate entries in the binding
  168.  *    table.  This is because every shared hash table and spinlock
  169.  *    has its name stored in the binding table at its creation.  It
  170.  *    is wasteful, in this case, but not much space is involved.
  171.  *
  172.  */
  173. LockTableId
  174. LockTabInit(tabName, conflictsP, prioP, ntypes)
  175. char *tabName;
  176. MASK    *conflictsP;
  177. int    *prioP;
  178. int     ntypes;
  179. {
  180.   LOCKTAB *ltable;
  181.   char *shmemName;
  182.   HASHCTL info;
  183.   int hash_flags;
  184.   Boolean    found;
  185.   int status = TRUE;
  186.  
  187.   if (ntypes > MAX_LOCKTYPES)
  188.   {
  189.     elog(NOTICE,"LockTabInit: too many lock types %d greater than %d",
  190.      ntypes,MAX_LOCKTYPES);
  191.     return(INVALID_TABLEID);
  192.   }
  193.  
  194.   if (NumTables > MAX_TABLES)
  195.   {
  196.     elog(NOTICE,
  197.      "LockTabInit: system limit of MAX_TABLES (%d) lock tables",
  198.      MAX_TABLES);
  199.     return(INVALID_TABLEID);
  200.   }
  201.  
  202.   /* allocate a string for the binding table lookup */
  203.   shmemName = (char *) palloc((unsigned)(strlen(tabName)+32));
  204.   if (! shmemName)
  205.   {
  206.     elog(NOTICE,"LockTabInit: couldn't malloc string %s \n",tabName);
  207.     return(INVALID_TABLEID);
  208.   }
  209.  
  210.   /* each lock table has a non-shared header */
  211.   ltable = (LOCKTAB *) palloc((unsigned) sizeof(LOCKTAB));
  212.   if (! ltable)
  213.   {
  214.     elog(NOTICE,"LockTabInit: couldn't malloc lock table %s\n",tabName);
  215.     (void) pfree (shmemName);
  216.     return(INVALID_TABLEID);
  217.   }
  218.  
  219.   /* ------------------------
  220.    * find/acquire the spinlock for the table
  221.    * ------------------------
  222.    */
  223.    SpinAcquire(LockMgrLock);
  224.  
  225.  
  226.   /* -----------------------
  227.    * allocate a control structure from shared memory or attach to it
  228.    * if it already exists.
  229.    * -----------------------
  230.    */
  231.   sprintf(shmemName,"%s (ctl)",tabName);
  232.   ltable->ctl = (LOCKCTL *)
  233.     ShmemInitStruct(shmemName,(unsigned)sizeof(LOCKCTL),&found);
  234.  
  235.   if (! ltable->ctl)
  236.   {
  237.     elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
  238.     status = FALSE;
  239.   }
  240.  
  241.   /* ----------------
  242.    * we're first - initialize
  243.    * ----------------
  244.    */
  245.   if (! found)
  246.   {
  247.     bzero(ltable->ctl,sizeof(LOCKCTL));
  248.     ltable->ctl->masterLock = LockMgrLock;
  249.     ltable->ctl->tableId = NumTables;
  250.   }
  251.  
  252.   /* --------------------
  253.    * other modules refer to the lock table by a tableId
  254.    * --------------------
  255.    */
  256.   AllTables[NumTables] = ltable;
  257.   NumTables++;
  258.   Assert(NumTables <= MAX_TABLES);
  259.  
  260.   /* ----------------------
  261.    * allocate a hash table for the lock tags.  This is used
  262.    * to find the different locks.
  263.    * ----------------------
  264.    */
  265.   info.keysize =  sizeof(LOCKTAG);
  266.   info.datasize = sizeof(LOCK);
  267.   info.hash = tag_hash;
  268.   hash_flags = (HASH_ELEM | HASH_FUNCTION);
  269.  
  270.   sprintf(shmemName,"%s (lock hash)",tabName);
  271.   ltable->lockHash = (HTAB *) ShmemInitHash(shmemName,
  272.           INIT_TABLE_SIZE,MAX_TABLE_SIZE,
  273.           &info,hash_flags);
  274.  
  275.   Assert( ltable->lockHash->hash == tag_hash);
  276.   if (! ltable->lockHash)
  277.   {
  278.     elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
  279.     status = FALSE;
  280.   }
  281.  
  282.   /* -------------------------
  283.    * allocate an xid table.  When different transactions hold
  284.    * the same lock, additional information must be saved (locks per tx).
  285.    * -------------------------
  286.    */
  287.   info.keysize = XID_TAGSIZE;
  288.   info.datasize = sizeof(XIDLookupEnt);
  289.   info.hash = tag_hash;
  290.   hash_flags = (HASH_ELEM | HASH_FUNCTION);
  291.  
  292.   sprintf(shmemName,"%s (xid hash)",tabName);
  293.   ltable->xidHash = (HTAB *) ShmemInitHash(shmemName,
  294.           INIT_TABLE_SIZE,MAX_TABLE_SIZE,
  295.           &info,hash_flags);
  296.  
  297.   if (! ltable->xidHash)
  298.   {
  299.     elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
  300.     status = FALSE;
  301.   }
  302.  
  303.   /* init ctl data structures */
  304.   LockTypeInit(ltable, conflictsP, prioP, ntypes);
  305.  
  306.   SpinRelease(LockMgrLock);
  307.  
  308.   (void) pfree (shmemName);
  309.  
  310.   if (status)
  311.     return(ltable->ctl->tableId);
  312.   else
  313.     return(INVALID_TABLEID);
  314. }
  315.  
  316. /*
  317.  * LockTabRename -- allocate another tableId to the same
  318.  *    lock table.
  319.  *
  320.  * NOTES: Both the lock module and the lock chain (lchain.c)
  321.  *    module use table id's to distinguish between different
  322.  *    kinds of locks.  Short term and long term locks look
  323.  *    the same to the lock table, but are handled differently
  324.  *    by the lock chain manager.  This function allows the
  325.  *    client to use different tableIds when acquiring/releasing
  326.  *    short term and long term locks.
  327.  */
  328. LockTableId
  329. LockTabRename(tableId)
  330. LockTableId    tableId;
  331. {
  332.   LockTableId    newTableId;
  333.  
  334.   if (NumTables >= MAX_TABLES)
  335.   {
  336.     return(INVALID_TABLEID);
  337.   }
  338.   if (AllTables[tableId] == INVALID_TABLEID)
  339.   {
  340.     return(INVALID_TABLEID);
  341.   }
  342.  
  343.   /* other modules refer to the lock table by a tableId */
  344.   newTableId = NumTables;
  345.   NumTables++;
  346.  
  347.   AllTables[newTableId] = AllTables[tableId];
  348.   return(newTableId);
  349. }
  350.  
  351. /*
  352.  * LockAcquire -- Check for lock conflicts, sleep if conflict found,
  353.  *    set lock if/when no conflicts.
  354.  *
  355.  * Returns: TRUE if parameters are correct, FALSE otherwise.
  356.  *
  357.  * Side Effects: The lock is always acquired.  No way to abort
  358.  *    a lock acquisition other than aborting the transaction.
  359.  *    Lock is recorded in the lkchain.
  360.  */
  361. bool
  362. LockAcquire(tableId, lockName, lockt)
  363. LockTableId        tableId;
  364. LOCKTAG        *lockName;
  365. LOCKT        lockt;
  366. {
  367.   XIDLookupEnt    *result,item;
  368.   HTAB        *xidTable;
  369.   Boolean    found;
  370.   LOCK        *lock = NULL;
  371.   SPINLOCK     masterLock;
  372.   LOCKTAB     *ltable;
  373.   int         status;
  374.   TransactionId    myXid;
  375.  
  376.   Assert (tableId < NumTables);
  377.   ltable = AllTables[tableId];
  378.   if (!ltable)
  379.   {
  380.     elog(NOTICE,"LockAcquire: bad lock table %d",tableId);
  381.     return  (FALSE);
  382.   }
  383.  
  384.   if (LockingIsDisabled)
  385.   {
  386.     return(TRUE);
  387.   }
  388.  
  389.   LOCK_PRINT("Acquire",lockName,lockt);
  390.   masterLock = ltable->ctl->masterLock;
  391.  
  392.   SpinAcquire(masterLock);
  393.  
  394.   Assert( ltable->lockHash->hash == tag_hash);
  395.   lock = (LOCK *)hash_search(ltable->lockHash,(Pointer)lockName,HASH_ENTER,&found);
  396.  
  397.   if (! lock)
  398.   {
  399.     SpinRelease(masterLock);
  400.     elog(FATAL,"LockAcquire: lock table %d is corrupted",tableId);
  401.     return(FALSE);
  402.   }
  403.  
  404.   /* --------------------
  405.    * if there was nothing else there, complete initialization
  406.    * --------------------
  407.    */
  408.   if  (! found)
  409.   {
  410.     lock->mask = 0;
  411.     ProcQueueInit(&(lock->waitProcs));
  412.     bzero((char *)lock->holders,sizeof(int)*MAX_LOCKTYPES);
  413.     bzero((char *)lock->activeHolders,sizeof(int)*MAX_LOCKTYPES);
  414.     lock->nHolding = 0;
  415.     lock->nActive = 0;
  416.  
  417.     Assert ( BlockIdEquals(&(lock->tag.tupleId.blockData), &(lockName->tupleId.blockData)) );
  418.  
  419.   }
  420.  
  421.   /* ------------------
  422.    * add an element to the lock queue so that we can clear the
  423.    * locks at end of transaction.
  424.    * ------------------
  425.    */
  426.   xidTable = ltable->xidHash;
  427.   myXid = GetCurrentTransactionId();
  428.  
  429.   /* ------------------
  430.    * Zero out all of the tag bytes (this clears the padding bytes for long
  431.    * word alignment and ensures hashing consistency).
  432.    * ------------------
  433.    */
  434.   bzero(&item, XID_TAGSIZE);
  435.   TransactionIdStore(myXid, &item.tag.xid);
  436.   item.tag.lock = MAKE_OFFSET(lock);
  437.   item.tag.pid = MyPid;
  438.  
  439.   result = (XIDLookupEnt *)hash_search(xidTable, (Pointer)&item, HASH_ENTER, &found);
  440.   if (!result)
  441.   {
  442.     elog(NOTICE,"LockResolveConflicts: xid table corrupted");
  443.     return(STATUS_ERROR);
  444.   }
  445.   if (!found)
  446.   {
  447.     XID_PRINT("queueing XidEnt LockAcquire:", result);
  448.     ProcAddLock(&result->queue);
  449.     result->nHolding = 0;
  450.     bzero((char *)result->holders,sizeof(int)*MAX_LOCKTYPES);
  451.   }
  452.  
  453.   /* ----------------
  454.    * lock->nholding tells us how many processes have _tried_ to
  455.    * acquire this lock,  Regardless of whether they succeeded or
  456.    * failed in doing so.
  457.    * ----------------
  458.    */
  459.   lock->nHolding++;
  460.   lock->holders[lockt]++;
  461.  
  462.   /* --------------------
  463.    * If I'm the only one holding a lock, then there
  464.    * cannot be a conflict.  Need to subtract one from the
  465.    * lock's count since we just bumped the count up by 1 
  466.    * above.
  467.    * --------------------
  468.    */
  469.   if (result->nHolding == lock->nActive)
  470.   {
  471.     result->holders[lockt]++;
  472.     result->nHolding++;
  473.     GrantLock(lock, lockt);
  474.     SpinRelease(masterLock);
  475.     return(TRUE);
  476.   }
  477.  
  478.   Assert(result->nHolding <= lock->nActive);
  479.  
  480.   status = LockResolveConflicts(ltable, lock, lockt, myXid, (int) MyPid);
  481.  
  482.   if (status == STATUS_OK)
  483.   {
  484.     GrantLock(lock, lockt);
  485.   }
  486.   else if (status == STATUS_FOUND)
  487.   {
  488.     status = WaitOnLock(ltable, tableId, lock, lockt);
  489.     XID_PRINT("Someone granted me the lock", result);
  490.   }
  491.  
  492.   SpinRelease(masterLock);
  493.  
  494.   return(status == STATUS_OK);
  495. }
  496.  
  497. /* ----------------------------
  498.  * LockResolveConflicts -- test for lock conflicts
  499.  *
  500.  * NOTES:
  501.  *     Here's what makes this complicated: one transaction's
  502.  * locks don't conflict with one another.  When many processes
  503.  * hold locks, each has to subtract off the other's locks when
  504.  * determining whether or not any new lock acquired conflicts with
  505.  * the old ones.
  506.  *
  507.  *  For example, if I am already holding a WRITE_INTENT lock,
  508.  *  there will not be a conflict with my own READ_LOCK.  If I
  509.  *  don't consider the intent lock when checking for conflicts,
  510.  *  I find no conflict.
  511.  * ----------------------------
  512.  */
  513. LockResolveConflicts(ltable,lock,lockt,xid,pid)
  514. LOCKTAB    *ltable;
  515. LOCK    *lock;
  516. LOCKT    lockt;
  517. TransactionId    xid;
  518. int pid;
  519. {
  520.   XIDLookupEnt    *result,item;
  521.   int        *myHolders;
  522.   int        nLockTypes;
  523.   HTAB        *xidTable;
  524.   Boolean    found;
  525.   int        bitmask;
  526.   int         i,tmpMask;
  527.  
  528.   nLockTypes = ltable->ctl->nLockTypes;
  529.   xidTable = ltable->xidHash;
  530.  
  531.   /* ---------------------
  532.    * read my own statistics from the xid table.  If there
  533.    * isn't an entry, then we'll just add one.
  534.    *
  535.    * Zero out the tag, this clears the padding bytes for long
  536.    * word alignment and ensures hashing consistency.
  537.    * ------------------
  538.    */
  539.   bzero(&item, XID_TAGSIZE);
  540.   TransactionIdStore(xid, &item.tag.xid);
  541.   item.tag.lock = MAKE_OFFSET(lock);
  542.   item.tag.pid = pid;
  543.  
  544.   if (! (result = (XIDLookupEnt *)
  545.      hash_search(xidTable, (Pointer)&item, HASH_ENTER, &found)))
  546.   {
  547.     elog(NOTICE,"LockResolveConflicts: xid table corrupted");
  548.     return(STATUS_ERROR);
  549.   }
  550.   myHolders = result->holders;
  551.  
  552.   if (! found)
  553.   {
  554.     /* ---------------
  555.      * we're not holding any type of lock yet.  Clear
  556.      * the lock stats.
  557.      * ---------------
  558.      */
  559.     bzero(result->holders,
  560.       nLockTypes*sizeof(* (lock->holders)));
  561.     result->nHolding = 0;
  562.   }
  563.  
  564.   /* ----------------------------
  565.    * first check for global conflicts: If no locks conflict
  566.    * with mine, then I get the lock.
  567.    *
  568.    * Checking for conflict: lock->mask represents the types of
  569.    * currently held locks.  conflictTable[lockt] has a bit
  570.    * set for each type of lock that conflicts with mine.  Bitwise
  571.    * compare tells if there is a conflict.
  572.    * ----------------------------
  573.    */
  574.   if (! (ltable->ctl->conflictTab[lockt] & lock->mask))
  575.   {
  576.  
  577.     result->holders[lockt]++;
  578.     result->nHolding++;
  579.  
  580.     XID_PRINT("Conflict Resolved: updated xid entry stats", result);
  581.  
  582.     return(STATUS_OK);
  583.   }
  584.  
  585.   /* ------------------------
  586.    * Rats.  Something conflicts. But it could still be my own
  587.    * lock.  We have to construct a conflict mask
  588.    * that does not reflect our own locks.
  589.    * ------------------------
  590.    */
  591.   bitmask = 0;
  592.   tmpMask = 2;
  593.   for (i=1;i<=nLockTypes;i++, tmpMask <<= 1)
  594.   {
  595.     if (lock->activeHolders[i] - myHolders[i])
  596.     {
  597.       bitmask |= tmpMask;
  598.     }
  599.   }
  600.  
  601.   /* ------------------------
  602.    * now check again for conflicts.  'bitmask' describes the types
  603.    * of locks held by other processes.  If one of these
  604.    * conflicts with the kind of lock that I want, there is a
  605.    * conflict and I have to sleep.
  606.    * ------------------------
  607.    */
  608.   if (! (ltable->ctl->conflictTab[lockt] & bitmask))
  609.   {
  610.  
  611.     /* no conflict. Get the lock and go on */
  612.  
  613.     result->holders[lockt]++;
  614.     result->nHolding++;
  615.  
  616.     XID_PRINT("Conflict Resolved: updated xid entry stats", result);
  617.  
  618.     return(STATUS_OK);
  619.  
  620.   }
  621.  
  622.   return(STATUS_FOUND);
  623. }
  624.  
  625. int
  626. WaitOnLock(ltable, tableId, lock,lockt)
  627. LOCKTAB        *ltable;
  628. LOCK         *lock;
  629. LockTableId        tableId;
  630. LOCKT        lockt;
  631. {
  632.   PROC_QUEUE *waitQueue = &(lock->waitProcs);
  633.  
  634.   int prio = ltable->ctl->prio[lockt];
  635.  
  636.   /* the waitqueue is ordered by priority. I insert myself
  637.    * according to the priority of the lock I am acquiring.
  638.    *
  639.    * SYNC NOTE: I am assuming that the lock table spinlock
  640.    * is sufficient synchronization for this queue.  That
  641.    * will not be true if/when people can be deleted from
  642.    * the queue by a SIGINT or something.
  643.    */
  644.   LOCK_PRINT("WaitOnLock: sleeping on lock", (&lock->tag), lockt);
  645.   if (ProcSleep(waitQueue,
  646.         ltable->ctl->masterLock,
  647.                 lockt,
  648.                 prio,
  649.                 lock) != NO_ERROR)
  650.   {
  651.     /* -------------------
  652.      * This could have happend as a result of a deadlock, see HandleDeadLock()
  653.      * Decrement the lock nHolding and holders fields as we are no longer 
  654.      * waiting on this lock.
  655.      * -------------------
  656.      */
  657.     lock->nHolding--;
  658.     lock->holders[lockt]--;
  659.     SpinRelease(ltable->ctl->masterLock);
  660.     elog(WARN,"WaitOnLock: error on wakeup - Aborting this transaction");
  661.  
  662.     /* -------------
  663.      * There is no return from elog(WARN, ...)
  664.      * -------------
  665.      */
  666.   }
  667.  
  668.   return(STATUS_OK);
  669. }
  670.  
  671. /*
  672.  * LockRelease -- look up 'lockName' in lock table 'tableId' and
  673.  *    release it.
  674.  *
  675.  * Side Effects: if the lock no longer conflicts with the highest
  676.  *    priority waiting process, that process is granted the lock
  677.  *    and awoken. (We have to grant the lock here to avoid a
  678.  *    race between the waking process and any new process to
  679.  *    come along and request the lock).
  680.  */
  681. bool
  682. LockRelease(tableId, lockName, lockt)
  683. LockTableId    tableId;
  684. LOCKTAG    *lockName;
  685. LOCKT    lockt;
  686. {
  687.   LOCK        *lock = NULL;
  688.   SPINLOCK     masterLock;
  689.   Boolean    found;
  690.   LOCKTAB     *ltable;
  691.   int        status;
  692.   XIDLookupEnt    *result,item;
  693.   HTAB         *xidTable;
  694.   bool        wakeupNeeded = true;
  695.  
  696.   Assert (tableId < NumTables);
  697.   ltable = AllTables[tableId];
  698.   if (!ltable) {
  699.     elog(NOTICE, "ltable is null in LockRelease");
  700.     return (FALSE);
  701.   }
  702.  
  703.   if (LockingIsDisabled)
  704.   {
  705.     return(TRUE);
  706.   }
  707.  
  708.   LOCK_PRINT("Release",lockName,lockt);
  709.  
  710.   masterLock = ltable->ctl->masterLock;
  711.   xidTable = ltable->xidHash;
  712.  
  713.   SpinAcquire(masterLock);
  714.  
  715.   Assert( ltable->lockHash->hash == tag_hash);
  716.   lock = (LOCK *)
  717.     hash_search(ltable->lockHash,(Pointer)lockName,HASH_FIND_SAVE,&found);
  718.  
  719.   /* let the caller print its own error message, too.
  720.    * Do not elog(WARN).
  721.    */
  722.   if (! lock)
  723.   {
  724.     SpinRelease(masterLock);
  725.     elog(NOTICE,"LockRelease: locktable corrupted");
  726.     return(FALSE);
  727.   }
  728.  
  729.   if (! found)
  730.   {
  731.     SpinRelease(masterLock);
  732.     elog(NOTICE,"LockRelease: locktable lookup failed, no lock");
  733.     return(FALSE);
  734.   }
  735.  
  736.   Assert(lock->nHolding > 0);
  737.  
  738.   /*
  739.    * fix the general lock stats
  740.    */
  741.   lock->nHolding--;
  742.   lock->holders[lockt]--;
  743.   lock->nActive--;
  744.   lock->activeHolders[lockt]--;
  745.  
  746.   Assert(lock->nActive >= 0);
  747.  
  748.   if (! lock->nHolding)
  749.   {
  750.     /* ------------------
  751.      * if there's no one waiting in the queue,
  752.      * we just released the last lock.
  753.      * Delete it from the lock table.
  754.      * ------------------
  755.      */
  756.     Assert( ltable->lockHash->hash == tag_hash);
  757.     lock = (LOCK *) hash_search(ltable->lockHash,
  758.                 (Pointer) &(lock->tag),
  759.                 HASH_REMOVE_SAVED,
  760.                 &found);
  761.     Assert(lock && found);
  762.     wakeupNeeded = false;
  763.   }
  764.  
  765.   /* ------------------
  766.    * Zero out all of the tag bytes (this clears the padding bytes for long
  767.    * word alignment and ensures hashing consistency).
  768.    * ------------------
  769.    */
  770.   bzero(&item, XID_TAGSIZE);
  771.  
  772.   TransactionIdStore(GetCurrentTransactionId(), &item.tag.xid);
  773.   item.tag.lock = MAKE_OFFSET(lock);
  774.   item.tag.pid = MyPid;
  775.  
  776.   if (! ( result = (XIDLookupEnt *) hash_search(xidTable,
  777.                         (Pointer)&item,
  778.                         HASH_FIND_SAVE,
  779.                         &found) )
  780.      || !found)
  781.   {
  782.     SpinRelease(masterLock);
  783.     elog(NOTICE,"LockReplace: xid table corrupted");
  784.     return(FALSE);
  785.   }
  786.   /*
  787.    * now check to see if I have any private locks.  If I do,
  788.    * decrement the counts associated with them.
  789.    */
  790.   result->holders[lockt]--;
  791.   result->nHolding--;
  792.  
  793.   XID_PRINT("LockRelease updated xid stats", result);
  794.  
  795.   /*
  796.    * If this was my last hold on this lock, delete my entry
  797.    * in the XID table.
  798.    */
  799.   if (! result->nHolding)
  800.   {
  801.     SHMQueueDelete(&result->queue);
  802.     if (! (result = (XIDLookupEnt *)
  803.        hash_search(xidTable, (Pointer)&item, HASH_REMOVE_SAVED, &found)) ||
  804.     ! found)
  805.     {
  806.       SpinRelease(masterLock);
  807.       elog(NOTICE,"LockReplace: xid table corrupted");
  808.       return(FALSE);
  809.     }
  810.   }
  811.  
  812.   /* --------------------------
  813.    * If there are still active locks of the type I just released, no one
  814.    * should be woken up.  Whoever is asleep will still conflict
  815.    * with the remaining locks.
  816.    * --------------------------
  817.    */
  818.   if (! (lock->activeHolders[lockt]))
  819.   {
  820.     /* change the conflict mask.  No more of this lock type. */
  821.     lock->mask &= BITS_OFF[lockt];
  822.   }
  823.  
  824.   if (wakeupNeeded)
  825.   {
  826.     /* --------------------------
  827.      * Wake the first waiting process and grant him the lock if it
  828.      * doesn't conflict.  The woken process must record the lock
  829.      * himself.
  830.      * --------------------------
  831.      */
  832.     (void) ProcLockWakeup(&(lock->waitProcs), (char *) ltable, (char *) lock);
  833.   }
  834.  
  835.   SpinRelease(masterLock);
  836.   return(TRUE);
  837. }
  838.  
  839. /*
  840.  * GrantLock -- udpate the lock data structure to show
  841.  *    the new lock holder.
  842.  */
  843. void
  844. GrantLock(lock, lockt)
  845. LOCK     *lock;
  846. LOCKT    lockt;
  847. {
  848.   lock->nActive++;
  849.   lock->activeHolders[lockt]++;
  850.   lock->mask |= BITS_ON[lockt];
  851. }
  852.  
  853. bool
  854. LockReleaseAll(tableId,lockQueue)
  855. LockTableId        tableId;
  856. SHM_QUEUE    *lockQueue;
  857. {
  858.   PROC_QUEUE     *waitQueue;
  859.   int        done;
  860.   XIDLookupEnt    *xidLook = NULL;
  861.   XIDLookupEnt    *tmp = NULL;
  862.   SHMEM_OFFSET     end = MAKE_OFFSET(lockQueue);
  863.   SPINLOCK     masterLock;
  864.   LOCKTAB     *ltable;
  865.   int        i,nLockTypes;
  866.   LOCK        *lock;
  867.   Boolean    found;
  868.  
  869.   Assert (tableId < NumTables);
  870.   ltable = AllTables[tableId];
  871.   if (!ltable)
  872.     return (FALSE);
  873.  
  874.   nLockTypes = ltable->ctl->nLockTypes;
  875.   masterLock = ltable->ctl->masterLock;
  876.  
  877.   if (SHMQueueEmpty(lockQueue))
  878.     return TRUE;
  879.  
  880.   SHMQueueFirst(lockQueue,&xidLook,&xidLook->queue);
  881.  
  882.   XID_PRINT("LockReleaseAll:", xidLook);
  883.  
  884.   SpinAcquire(masterLock);
  885.   for (;;)
  886.   {
  887.     /* ---------------------------
  888.      * XXX Here we assume the shared memory queue is circular and
  889.      * that we know its internal structure.  Should have some sort of
  890.      * macros to allow one to walk it.  mer 20 July 1991
  891.      * ---------------------------
  892.      */
  893.     done = (xidLook->queue.next == end);
  894.     lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
  895.  
  896.     LOCK_PRINT("ReleaseAll",(&lock->tag),0);
  897.  
  898.     /* ------------------
  899.      * fix the general lock stats
  900.      * ------------------
  901.      */
  902.     if (lock->nHolding != xidLook->nHolding)
  903.     {
  904.       lock->nHolding -= xidLook->nHolding;
  905.       lock->nActive -= xidLook->nHolding;
  906.       Assert(lock->nActive >= 0);
  907.       for (i=1; i<=nLockTypes; i++)
  908.       {
  909.     lock->holders[i] -= xidLook->holders[i];
  910.     lock->activeHolders[i] -= xidLook->holders[i];
  911.     if (! lock->activeHolders[i])
  912.       lock->mask &= BITS_OFF[i];
  913.       }
  914.     }
  915.     else
  916.     {
  917.       /* --------------
  918.        * set nHolding to zero so that we can garbage collect the lock
  919.        * down below...
  920.        * --------------
  921.        */
  922.       lock->nHolding = 0;
  923.     }
  924.     /* ----------------
  925.      * always remove the xidLookup entry, we're done with it now
  926.      * ----------------
  927.      */
  928.     if ((! hash_search(ltable->xidHash, (Pointer)xidLook, HASH_REMOVE, &found))
  929.         || !found)
  930.     {
  931.       SpinRelease(masterLock);
  932.       elog(NOTICE,"LockReplace: xid table corrupted");
  933.       return(FALSE);
  934.     }
  935.  
  936.     if (! lock->nHolding)
  937.     {
  938.       /* --------------------
  939.        * if there's no one waiting in the queue, we've just released
  940.        * the last lock.
  941.        * --------------------
  942.        */
  943.  
  944.       Assert( ltable->lockHash->hash == tag_hash);
  945.       lock = (LOCK *)
  946.     hash_search(ltable->lockHash,(Pointer)&(lock->tag),HASH_REMOVE, &found);
  947.       if ((! lock) || (!found))
  948.       {
  949.     SpinRelease(masterLock);
  950.     elog(NOTICE,"LockReplace: cannot remove lock from HTAB");
  951.     return(FALSE);
  952.       }
  953.     }
  954.     else
  955.     {
  956.       /* --------------------
  957.        * Wake the first waiting process and grant him the lock if it
  958.        * doesn't conflict.  The woken process must record the lock
  959.        * him/herself.
  960.        * --------------------
  961.        */
  962.       waitQueue = &(lock->waitProcs);
  963.       (void) ProcLockWakeup(waitQueue, (char *) ltable, (char *) lock);
  964.     }
  965.  
  966.     if (done)
  967.       break;
  968.     SHMQueueFirst(&xidLook->queue,&tmp,&tmp->queue);
  969.     xidLook = tmp;
  970.   }
  971.   SpinRelease(masterLock);
  972.   SHMQueueInit(lockQueue);
  973.   return TRUE;
  974. }
  975.  
  976. int
  977. LockShmemSize()
  978. {
  979.     int size;
  980.     int nLockBuckets, nLockSegs;
  981.     int nXidBuckets, nXidSegs;
  982.  
  983.     nLockBuckets = 1 << (int)my_log2((NLOCKENTS - 1) / DEF_FFACTOR + 1);
  984.     nLockSegs = 1 << (int)my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
  985.  
  986.     nXidBuckets = 1 << (int)my_log2((NLOCKS_PER_XACT-1) / DEF_FFACTOR + 1);
  987.     nXidSegs = 1 << (int)my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
  988.  
  989.     size =    NLOCKENTS*sizeof(LOCK) +
  990.         NBACKENDS*sizeof(XIDLookupEnt) +
  991.         NBACKENDS*sizeof(PROC) +
  992.         sizeof(LOCKCTL) +
  993.         sizeof(PROC_HDR) +
  994.         nLockSegs*DEF_SEGSIZE*sizeof(SEGMENT) +
  995.         my_log2(NLOCKENTS) + sizeof(HHDR) +
  996.         nXidSegs*DEF_SEGSIZE*sizeof(SEGMENT) +
  997.         my_log2(NBACKENDS) + sizeof(HHDR);
  998.  
  999.     return size;
  1000. }
  1001.  
  1002. /* -----------------
  1003.  * Boolean function to determine current locking status
  1004.  * -----------------
  1005.  */
  1006. bool
  1007. LockingDisabled()
  1008. {
  1009.     return LockingIsDisabled;
  1010. }
  1011.